<?php


namespace App\Traits;

use Hyperf\HttpMessage\Stream\SwooleStream;
use Hyperf\Utils\Codec\Json;
use Hyperf\Utils\Context;
use Hyperf\Utils\Contracts\Arrayable;
use Hyperf\Utils\Contracts\Jsonable;
use Psr\Http\Message\ResponseInterface;

/**
 * Trait ApiResponseTrait
 * @author Colorado
 * @package App\Traits
 */
trait ApiResponseTrait
{
    protected $response;
    private int $httpCode = 200;
    private int $errorCode = 400;
    private string $errorMsg = '系统错误';
    private array $headers = [];

    /**
     * 成功响应
     * @param mixed $data
     * @param string $msg
     * @return ResponseInterface
     */
    public function success(mixed $data = [], $msg = '响应成功'): ResponseInterface
    {
        return $this->respond([
            'code' => $this->httpCode,
            'msg' => $msg,
            'data' => $data
        ]);
    }

    /**
     * @param null|array|Arrayable|Jsonable|string $response
     * @return ResponseInterface
     */
    private function respond(array|string|Jsonable|Arrayable|null $response): ResponseInterface
    {
        if (is_string($response)) {
            return $this->response()
                ->withAddedHeader('content-type', 'text/plain')
                ->withBody(new SwooleStream($response));
        }

        if (is_array($response) || $response instanceof Arrayable) {
            return $this->response()
                ->withAddedHeader('content-type', 'application/json')
                ->withBody(new SwooleStream(Json::encode($response)));
        }

        if ($response instanceof Jsonable) {
            return $this->response()
                ->withAddedHeader('content-type', 'application/json')
                ->withBody(new SwooleStream((string)$response));
        }

        return $this->response()
            ->withAddedHeader('content-type', 'text/plain')
            ->withBody(new SwooleStream((string)$response));
    }

    /**
     * 获取 Response 对象
     * @return ResponseInterface
     */
    protected function response(): ResponseInterface
    {
        $response = Context::get(ResponseInterface::class);
        foreach ($this->headers as $key => $value) {
            $response = $response->withHeader($key, $value);
        }
        return $response;
    }

    /**
     * 错误返回
     * @param int|null $code
     * @param string|null $msg
     * @param array $data 额外返回的数据
     * @return ResponseInterface
     */
    public function error(int $code = null, string $msg = null, array $data = []): ResponseInterface
    {
        return $this->setHttpCode($this->httpCode == 200 ? 400 : $this->httpCode)
            ->respond([
                'code' => $code ?? $this->errorCode,
                'msg' => $msg ?? $this->errorMsg,
                'data' => $data
            ]);
    }

    /**
     * 设置http返回码
     * @param int $code http返回码
     * @return $this
     */
    final public function setHttpCode(int $code = 200): self
    {
        $this->httpCode = $code;
        return $this;
    }

    /**
     * 设置返回头部header值
     * @param string $key
     * @param        $value
     * @return $this
     */
    public function addHttpHeader(string $key, $value): self
    {
        $this->headers += [$key => $value];
        return $this;
    }

    /**
     * 批量设置头部返回
     * @param array $headers header数组：[key1 => value1, key2 => value2]
     * @return $this
     */
    public function addHttpHeaders(array $headers = []): self
    {
        $this->headers += $headers;
        return $this;
    }
}